package kq

import (
	"context"
	"encoding/json"
	"fmt"
	"strconv"

	"mall/common/globalkey"
	"mall/common/moneyx"
	"mall/common/mqueuex"
	"mall/common/resultx"
	"mall/common/utils/pointy"
	enum "mall/service/backend/common/enum/user"
	"mall/service/backend/rmq/internal/svc"
	"mall/service/order/rpc/orderclient"
	"mall/service/user/rpc/userclient"

	"github.com/dtm-labs/client/dtmcli/dtmimp"
	"github.com/dtm-labs/client/dtmgrpc"
	"github.com/pkg/errors"
	// "github.com/sirupsen/logrus"
	"github.com/zeromicro/go-zero/core/logx"
)

var OrderUpdateTradeStateError = resultx.NewErrCode(resultx.ORDER_UPDATE_TRADE_STATE_FAILED)

/**
 * Listening to the payment flow status change notification message queue
 */
type ThirdPartPaymentUpdateTradeStateMq struct {
	ctx    context.Context
	svcCtx *svc.ServiceContext
}

func NewThirdPartPaymentUpdateTradeStateMq(ctx context.Context, svcCtx *svc.ServiceContext) *ThirdPartPaymentUpdateTradeStateMq {
	return &ThirdPartPaymentUpdateTradeStateMq{
		ctx:    ctx,
		svcCtx: svcCtx,
	}
}

func (l *ThirdPartPaymentUpdateTradeStateMq) Consume(_, val string) error {
	// 解析数据
	var message mqueuex.ThirdPartPaymentUpdateTradeStateMessage
	if err := json.Unmarshal([]byte(val), &message); err != nil {
		// logx.WithContext(l.ctx).Error("ThirdPartPaymentUpdateTradeStateMq.Consume Unmarshal err : %v , val : %s", err, val)
		logx.Errorw("ThirdPartPaymentUpdateTradeStateMq.Consume json.Unmarshal err", logx.Field("detail", err.Error()))
		return err
	}

	// 执行业务..
	if err := l.execService(&message); err != nil {
		// logx.WithContext(l.ctx).Error("ThirdPartPaymentUpdateTradeStateMq.execService err : %v , val : %s , message: %+v", err, val, message)
		logx.Errorw("ThirdPartPaymentUpdateTradeStateMq.execService err", logx.Field("detail", err.Error()),
			logx.Field("val", val), logx.Field("message", fmt.Sprintf("%+v", message)))
		return err
	}

	return nil
}

// Verify and update relevant flow data
func (l *ThirdPartPaymentUpdateTradeStateMq) execService(message *mqueuex.ThirdPartPaymentUpdateTradeStateMessage) error {
	// logrus.Info(fmt.Sprintf("ThirdPartPaymentUpdateTradeStateMq execService message: %+v", message))

	if message.Total == nil || message.OutTradeNo == nil || message.TradeState == nil {
		return errors.Wrapf(OrderUpdateTradeStateError, "Failed to get paid order, message: %+v ", message)
	}

	order, err := l.svcCtx.OrderRpc.GetOrderBySn(l.ctx, &orderclient.GetOrderBySnReq{
		PaymentNo:   message.OutTradeNo,
		WithPayment: pointy.GetPointer(uint32(1)),
	})
	// logrus.Info(fmt.Sprintf("ThirdPartPaymentUpdateTradeStateMq execService order: %+v", order))
	if err != nil {
		return errors.Wrapf(OrderUpdateTradeStateError, "Failed to get paid order err: %v , message: %+v ", err, message)
	}

	// if order.Id == nil || order.TradeState == nil || order.UserId == nil || order.GemAmount == nil || order.Sn == nil {
	if order.Id == nil || order.TradeState == nil || order.UserId == nil || order.Sn == nil {
		return errors.Wrapf(OrderUpdateTradeStateError, "Failed to get valid data of paid order: %+v ", order)
	}

	if len(order.Payments) > 0 {
		payment := order.Payments[0]
		if payment.Amount != nil && len(*payment.Amount) > 0 {
			if fa, err := moneyx.ParseDecimal(*payment.Amount); err != nil {
				return errors.Wrapf(OrderUpdateTradeStateError, "Failed to get paid amount err: %v , amount: %s ", err, *payment.Amount)
			} else {
				amount := moneyx.FormatDecimalToFen(fa)
				// 比对金额
				if amount != *message.Total {
					return errors.Wrapf(OrderUpdateTradeStateError, "Paid order amount exception, amount: %v , message: %v ", amount, message)
				}

				// Judgment trade state
				paymentTradeState, orderTradeState := l.parseTradeStateFromThirdPartPayment(*message.TradeState)
				if paymentTradeState == globalkey.ThirdPartPaymentTradeStateSuccess {
					// Payment Notification.
					if payment.Status == nil || *payment.Status != globalkey.OrderTradeStateNotPay {
						logx.Errorw("ThirdPartPaymentUpdateTradeStateMq execService payment.Status exception", logx.Field("detail", strconv.FormatInt(int64(*payment.Status), 10)))
						return nil
					}

					// Update the flow status.
					// err = l.updateTradeStateDtmSaga(order.Id, &orderTradeState, order.TradeState, payment.Id, order.UserId, order.GemAmount, order.Sn)
					err = l.updateTradeStateDtmSaga(order.Id, &orderTradeState, order.TradeState, payment.Id, message.TransactionId)
					if err != nil {
						return errors.Wrapf(OrderUpdateTradeStateError, "update order tradeState fail, err: %v , message: %+v", err, message)
					}
				} else if paymentTradeState == globalkey.ThirdPartPaymentTradeStateNotPay {
					// Refund notification @todo to be done later, not needed at this time
				}
			}
		}
	}

	return nil
}

func (l *ThirdPartPaymentUpdateTradeStateMq) parseTradeStateFromThirdPartPayment(weChatPayTradeState string) (uint32, uint32) {
	switch weChatPayTradeState {
	case globalkey.WeChatPayTradeStateNotPay: // 未支付
		return globalkey.ThirdPartPaymentTradeStateNotPay, globalkey.OrderTradeStateNotPay
	case globalkey.WeChatPayTradeStateUserPaying: // 用户支付中（付款码支付）
		return globalkey.ThirdPartPaymentTradeStateUserPaying, globalkey.OrderTradeStateNotPay
	case globalkey.WeChatPayTradeStateRevoked: // 已撤销（付款码支付）
		return globalkey.ThirdPartPaymentTradeStateRevoked, globalkey.OrderTradeStateNotPay
	case globalkey.WeChatPayTradeStateSuccess: // 支付成功
		return globalkey.ThirdPartPaymentTradeStateSuccess, globalkey.OrderTradeStatePaid
	case globalkey.WeChatPayTradeStatePayError: // 支付失败（其他原因，如银行返回失败）
		return globalkey.ThirdPartPaymentTradeStatePayError, globalkey.OrderTradeStateNotPay
	case globalkey.WeChatPayTradeStateClosed: // 已关闭
		return globalkey.ThirdPartPaymentTradeStateClosed, globalkey.OrderTradeStateClosed
	case globalkey.WeChatPayTradeStateRefund: // 已退款
		return globalkey.ThirdPartPaymentTradeStateRefund, globalkey.OrderTradeStateRefunded
	}

	return uint32(0), uint32(0)
}

func (l *ThirdPartPaymentUpdateTradeStateMq) updateTradeStateDtmSaga(
	orderId *uint64,
	tradeState *uint32,
	tradeStateRevert *uint32,
	paymentId *uint64,
	transactionId *string,
) error {
	// 获取 OrderRpc BuildTarget
	orderRpcBusiServer, err := l.svcCtx.Config.OrderRpc.BuildTarget()
	if err != nil {
		return err
		// return fmt.Errorf("下单异常超时")
	}

	// DefaultGrpcServer default url for grpc server.
	defaultGrpcServer := l.svcCtx.Config.DefaultGrpcServer

	// 创建一个gid
	gid := dtmgrpc.MustGenGid(defaultGrpcServer)

	// 创建一个saga协议的事务
	saga := dtmgrpc.NewSagaGrpc(defaultGrpcServer, gid).
		Add(
			orderRpcBusiServer+"/order.Order/UpdateTradeStateRaw",
			orderRpcBusiServer+"/order.Order/UpdateTradeStateRevert",
			&orderclient.UpdateTradeStateReq{
				Id:               orderId,
				TradeState:       tradeState,
				TradeStateRevert: tradeStateRevert,
				PaymentId:        paymentId,
				TransactionId:    transactionId,
			})

	// 事务提交
	err = saga.Submit()
	dtmimp.FatalIfError(err)
	if err != nil {
		return err
		// return fmt.Errorf("submit data to dtm-server err : %+v \n", err)
	}

	return nil
}

func (l *ThirdPartPaymentUpdateTradeStateMq) updateTradeStateDtmSagaBak(
	orderId *uint64,
	tradeState *uint32,
	tradeStateRevert *uint32,
	paymentId *uint64,
	userId *uint64,
	amount *string,
	orderSn *string,
) error {
	// 获取 OrderRpc BuildTarget
	orderRpcBusiServer, err := l.svcCtx.Config.OrderRpc.BuildTarget()
	if err != nil {
		return err
		// return fmt.Errorf("下单异常超时")
	}

	// 获取 UserRpc BuildTarget
	userRpcBusiServer, err := l.svcCtx.Config.UserRpc.BuildTarget()
	if err != nil {
		return err
	}

	// DefaultGrpcServer default url for grpc server.
	defaultGrpcServer := l.svcCtx.Config.DefaultGrpcServer

	// 创建一个gid
	gid := dtmgrpc.MustGenGid(defaultGrpcServer)

	// 创建一个saga协议的事务
	saga := dtmgrpc.NewSagaGrpc(defaultGrpcServer, gid).
		Add(
			orderRpcBusiServer+"/order.Order/UpdateTradeStateRaw",
			orderRpcBusiServer+"/order.Order/UpdateTradeStateRevert",
			&orderclient.UpdateTradeStateReq{
				Id:               orderId,
				TradeState:       tradeState,
				TradeStateRevert: tradeStateRevert,
				PaymentId:        paymentId,
			}).
		Add(
			userRpcBusiServer+"/user.User/UpdateUserAssetRaw",
			userRpcBusiServer+"/user.User/UpdateUserAssetRevert",
			&userclient.UpdateUserAssetReq{
				UserId:       userId,
				AssetType:    pointy.GetPointer(enum.UserAssetTypeGem),            // 宝石
				ChangeType:   pointy.GetPointer(enum.UserAssetChangeTypeIncrease), // 增加
				ChangeAmount: amount,
				SourceType:   pointy.GetPointer(enum.UserAssetSourceTypeCharge), // 充值
				SourceId:     orderId,
				SourceDesc:   orderSn,
			})

	// 事务提交
	err = saga.Submit()
	dtmimp.FatalIfError(err)
	if err != nil {
		return err
		// return fmt.Errorf("submit data to dtm-server err : %+v \n", err)
	}

	return nil
}
